﻿Imports System
Imports System.Collections.Generic
Imports System.IO
Imports System.Linq
Imports System.Web
Imports Lucene.Net.Analysis.Standard
Imports Lucene.Net.Documents
Imports Lucene.Net.Index
Imports Lucene.Net.QueryParsers
Imports Lucene.Net.Search
Imports Lucene.Net.Store
Imports Version = Lucene.Net.Util.Version


Public NotInheritable Class GoLucene
    Private Sub New()
    End Sub
    ' idiotites
    Public Shared _luceneDir As String = Path.Combine(HttpContext.Current.Request.PhysicalApplicationPath, "lucene_index")
    Private Shared _directoryTemp As FSDirectory
    Private Shared ReadOnly Property _directory() As FSDirectory
        Get
            If _directoryTemp Is Nothing Then
                _directoryTemp = FSDirectory.Open(New DirectoryInfo(_luceneDir))
            End If
            If IndexWriter.IsLocked(_directoryTemp) Then
                IndexWriter.Unlock(_directoryTemp)
            End If
            Dim lockFilePath = Path.Combine(_luceneDir, "write.lock")
            If File.Exists(lockFilePath) Then
                File.Delete(lockFilePath)
            End If
            Return _directoryTemp
        End Get
    End Property

    ' methodos anazitisis
    Public Shared Function GetAllIndexRecords() As IEnumerable(Of SampleData)

        If Not System.IO.Directory.GetFiles(_luceneDir).Any() Then
            Return New List(Of SampleData)()
        End If

        ' dimiourgia anazitis me thn boithia tis  lucene 
        Dim searcher = New IndexSearcher(_directory, False)
        Dim reader = IndexReader.Open(_directory, False)
        Dim docs = New List(Of Document)()
        Dim term = reader.TermDocs()
        While term.[Next]()
            docs.Add(searcher.Doc(term.Doc))
        End While
        reader.Dispose()
        searcher.Dispose()
        Return _mapLuceneToDataList(docs)
    End Function
    Public Shared Function Search(ByVal input As String, Optional ByVal fieldName As String = "") As IEnumerable(Of SampleData)
        If String.IsNullOrEmpty(input) Then
            Return New List(Of SampleData)()
        End If

        Dim terms = input.Trim().Replace("-", " ").Split(" "c).Where(Function(x) Not String.IsNullOrEmpty(x)).[Select](Function(x) x.Trim() + "*")
        input = String.Join(" ", terms)

        Return _search(input, fieldName)
    End Function
    Public Shared Function SearchDefault(ByVal input As String, Optional ByVal fieldName As String = "") As IEnumerable(Of SampleData)
        Return If(String.IsNullOrEmpty(input), New List(Of SampleData)(), _search(input, fieldName))
    End Function

    ' main methodos tis anazitisis
    Private Shared Function _search(ByVal searchQuery As String, Optional ByVal searchField As String = "") As IEnumerable(Of SampleData)
        ' epalhtheush twn apotelesmatwn
        If String.IsNullOrEmpty(searchQuery.Replace("*", "").Replace("?", "")) Then
            Return New List(Of SampleData)()
        End If

        ' dimiourgia anazitis me thn boithia tis  lucene 
        Using searcher = New IndexSearcher(_directory, False)
            Dim hits_limit = 1000
            Dim analyzer = New StandardAnalyzer(Version.LUCENE_30)

            ' anazitisi se memonomeno pedio
            If Not String.IsNullOrEmpty(searchField) Then
                Dim parser = New QueryParser(Version.LUCENE_30, searchField, analyzer)
                Dim query = parseQuery(searchQuery, parser)
                Dim hits = searcher.Search(query, hits_limit).ScoreDocs
                Dim results = _mapLuceneToDataList(hits, searcher)
                analyzer.Close()
                searcher.Dispose()
                Return results
            Else
                ' anazitisi se pollapla pedia 
                Dim parser = New MultiFieldQueryParser(Version.LUCENE_30, {"Id", "Name", "Year", "directory", "category", "Stars"}, analyzer)
                Dim query = parseQuery(searchQuery, parser)
                Dim hits = searcher.Search(query, Nothing, hits_limit, Sort.INDEXORDER).ScoreDocs
                Dim results = _mapLuceneToDataList(hits, searcher)
                analyzer.Close()
                searcher.Dispose()
                Return results
            End If
        End Using
    End Function
    Private Shared Function parseQuery(ByVal searchQuery As String, ByVal parser As QueryParser) As Query
        Dim query As Query
        Try
            query = parser.Parse(searchQuery.Trim())
        Catch generatedExceptionName As ParseException
            query = parser.Parse(QueryParser.Escape(searchQuery.Trim()))
        End Try
        Return query
    End Function

    'euretiriasi dedomenwn pros anazitisi 
    Private Shared Function _mapLuceneToDataList(ByVal hits As IEnumerable(Of Document)) As IEnumerable(Of SampleData)
        Return hits.[Select](AddressOf _mapLuceneDocumentToData).ToList()
    End Function
    Private Shared Function _mapLuceneToDataList(ByVal hits As IEnumerable(Of ScoreDoc), ByVal searcher As IndexSearcher) As IEnumerable(Of SampleData)
        Return hits.[Select](Function(hit) _mapLuceneDocumentToData(searcher.Doc(hit.Doc))).ToList()
    End Function
    Private Shared Function _mapLuceneDocumentToData(ByVal doc As Document) As SampleData
        Return New SampleData() With { _
         .movieID = Convert.ToInt32(doc.[Get]("Id")), _
         .movieName = doc.[Get]("Name"), _
         .Year = Convert.ToInt32(doc.[Get]("Year")), _
         .directory = doc.[Get]("directory"), _
         .category = doc.[Get]("category"), _
         .movieStars = Convert.ToInt32(doc.[Get]("Stars")) _
        }
    End Function

    ' prosthiki enimerwsh kai katharismos toy eurititioy dedomenwn
    Public Shared Sub AddUpdateLuceneIndex(ByVal sampleData As SampleData)
        AddUpdateLuceneIndex(New List(Of SampleData)() From { _
    sampleData _
   })
    End Sub
    Public Shared Sub AddUpdateLuceneIndex(ByVal sampleDatas As IEnumerable(Of SampleData))
        ' arxikopoihsh ths lucene
        Dim analyzer = New StandardAnalyzer(Version.LUCENE_30)
        Using writer = New IndexWriter(_directory, analyzer, IndexWriter.MaxFieldLength.UNLIMITED)
            ' prothiki dedomenwn sto euretitio tis lucene kai antikatastah twn palaioterwn
            For Each sampleData In sampleDatas
                _addToLuceneIndex(sampleData, writer)
            Next
            analyzer.Close()
            writer.Dispose()
        End Using
    End Sub
    Public Shared Sub ClearLuceneIndexRecord(ByVal record_id As Integer)
        ' arxikopoihsh ths lucene
        Dim analyzer = New StandardAnalyzer(Version.LUCENE_30)
        Using writer = New IndexWriter(_directory, analyzer, IndexWriter.MaxFieldLength.UNLIMITED)
            ' aferesh palioterwn euretiriwn 
            Dim searchQuery = New TermQuery(New Term("Id", record_id.ToString()))
            writer.DeleteDocuments(searchQuery)
            analyzer.Close()
            writer.Dispose()
        End Using
    End Sub
    Public Shared Function ClearLuceneIndex() As Boolean
        Try
            Dim analyzer = New StandardAnalyzer(Version.LUCENE_30)
            Using writer = New IndexWriter(_directory, analyzer, True, IndexWriter.MaxFieldLength.UNLIMITED)
                ' aferesh palioterwn euretiriwn 
                writer.DeleteAll()


                analyzer.Close()
                writer.Dispose()
            End Using
        Catch generatedExceptionName As Exception
            Return False
        End Try
        Return True
    End Function
    Public Shared Sub Optimize()
        Dim analyzer = New StandardAnalyzer(Version.LUCENE_30)
        Using writer = New IndexWriter(_directory, analyzer, IndexWriter.MaxFieldLength.UNLIMITED)
            analyzer.Close()
            writer.Optimize()
            writer.Dispose()
        End Using
    End Sub
    Private Shared Sub _addToLuceneIndex(ByVal sampleData As SampleData, ByVal writer As IndexWriter)
        ' aferesh palioterwn euretiriwn 
        Dim searchQuery = New TermQuery(New Term("Id", sampleData.movieID.ToString()))
        writer.DeleteDocuments(searchQuery)

        ' prosthiki kainourgiou
        Dim doc = New Document()

        ' prosthiki pediwn sti lucene
        doc.Add(New Field("Id", sampleData.movieID.ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED))
        doc.Add(New Field("Name", sampleData.movieName, Field.Store.YES, Field.Index.ANALYZED))
        doc.Add(New Field("Year", sampleData.Year.ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED))
        doc.Add(New Field("directory", sampleData.directory, Field.Store.YES, Field.Index.ANALYZED))
        doc.Add(New Field("category", sampleData.category, Field.Store.YES, Field.Index.ANALYZED))
        doc.Add(New Field("Stars", sampleData.movieStars.ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED))


        writer.AddDocument(doc)
    End Sub

End Class

